package data;

import java.util.Arrays;
import java.util.Random;

public class Breeding {
	
	//private static final double mutationRate = 0.5;
	private static final int genomeLength = 17;
	
	public static int[] doubleToBinary(double d){
		int[] binary = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};

		for(int i = genomeLength; i != 0; i--){
			if(binaryToDouble(binary) > d)
				binary[i] = 0;
			else
				binary[i] = 1;
			
			binary[i-1] = 1;
		}
		
		return binary;
		}
	
	public static double binaryToDouble(int[] binary){
		double d = 0;
		
		for(int i = 0; i < binary.length; i++){
			d += Math.pow(2, i)*binary[i];
		}
		d = d/(Math.pow(2, binary.length - 2)) - 2 ;
		
		return d;
	}
	
	public static int[] mutate(int[] binary){		
		for(int i = 0; i < binary.length; i++){
			if(Math.random() < Math.pow(0.75, i+2))
				binary[i] = 1 - binary[i];
		}
		
		
		return binary;
	}
	
	public static double splitBinary(int[] parent, int[] child){
		//int place = (1 + (int)(Math.random() * ((3 - 1) + 1))) + (1 + (int)(Math.random() * ((3 - 1) + 1))) + (1 + (int)(Math.random() * ((3 - 1) + 1))) + (1 + (int)(Math.random() * ((3 - 1) + 1)));
		/*for(int i = 0; i < parent.length; i++){
			if(i > place)
				child[i] = parent[i];
		}*/
		
		if(Math.random() < 0.5)
			child = parent;
		
		return binaryToDouble(child);
	}
	
	public static void newGeneration(MovementData[] bots){
		Random rand = new Random();
		int randomParent = 0;
		int elite = 4;
		Arrays.sort(bots);
	
		for(int i = 0; i < bots.length; i++)
			System.out.println(bots[i].speedData.bearing);
		
		for(int i = bots.length - 1; i >= bots.length/elite; i--){
			randomParent = rand.nextInt(elite);
			bots[i] = new MovementData(bots[randomParent]);
		}

		for(int i = 0; i < bots.length; i++)
			System.out.println(bots[i].speedData.bearing);

		
		for(int i = bots.length - 1; i > bots.length/elite ; i--){
			if(i > bots.length/elite - 1)
				randomParent = rand.nextInt(bots.length/elite);
			else
				randomParent = rand.nextInt(bots.length/elite + i - bots.length/elite);
			
			if(rand.nextDouble() > 0.5)
				bots[i].speedData = new RobotData(bots[randomParent].speedData);
			else
				bots[i].turnData = new RobotData(bots[randomParent].turnData);
/*			
 * 			
			bots[i].speedData.bearing = splitBinary(doubleToBinary(bots[randomParent].speedData.bearing), doubleToBinary(bots[i].speedData.bearing));
			bots[i].speedData.distanceToEnemy = splitBinary(doubleToBinary(bots[randomParent].speedData.distanceToEnemy), doubleToBinary(bots[i].speedData.distanceToEnemy));
			bots[i].speedData.headingEnemy = splitBinary(doubleToBinary(bots[randomParent].speedData.headingEnemy), doubleToBinary(bots[i].speedData.headingEnemy));
			bots[i].speedData.robotBackDistanceToWall = splitBinary(doubleToBinary(bots[randomParent].speedData.robotBackDistanceToWall), doubleToBinary(bots[i].speedData.robotBackDistanceToWall));
			bots[i].speedData.robotFrontDistanceToWall = splitBinary(doubleToBinary(bots[randomParent].speedData.robotFrontDistanceToWall), doubleToBinary(bots[i].speedData.robotFrontDistanceToWall));
			bots[i].speedData.robotLeftDistanceToWall = splitBinary(doubleToBinary(bots[randomParent].speedData.robotLeftDistanceToWall), doubleToBinary(bots[i].speedData.robotLeftDistanceToWall));
			bots[i].speedData.robotRightDistanceToWall = splitBinary(doubleToBinary(bots[randomParent].speedData.robotRightDistanceToWall), doubleToBinary(bots[i].speedData.robotRightDistanceToWall));
			bots[i].speedData.velocity = splitBinary(doubleToBinary(bots[randomParent].speedData.velocity), doubleToBinary(bots[i].speedData.velocity));
			
			bots[i].turnData.bearing = splitBinary(doubleToBinary(bots[randomParent].turnData.bearing), doubleToBinary(bots[i].turnData.bearing));
			bots[i].turnData.distanceToEnemy = splitBinary(doubleToBinary(bots[randomParent].turnData.distanceToEnemy), doubleToBinary(bots[i].turnData.distanceToEnemy));
			bots[i].turnData.headingEnemy = splitBinary(doubleToBinary(bots[randomParent].turnData.headingEnemy), doubleToBinary(bots[i].turnData.headingEnemy));
			bots[i].turnData.robotBackDistanceToWall = splitBinary(doubleToBinary(bots[randomParent].turnData.robotBackDistanceToWall), doubleToBinary(bots[i].turnData.robotBackDistanceToWall));
			bots[i].turnData.robotFrontDistanceToWall = splitBinary(doubleToBinary(bots[randomParent].turnData.robotFrontDistanceToWall), doubleToBinary(bots[i].turnData.robotFrontDistanceToWall));
			bots[i].turnData.robotLeftDistanceToWall = splitBinary(doubleToBinary(bots[randomParent].turnData.robotLeftDistanceToWall), doubleToBinary(bots[i].turnData.robotLeftDistanceToWall));
			bots[i].turnData.robotRightDistanceToWall = splitBinary(doubleToBinary(bots[randomParent].turnData.robotRightDistanceToWall), doubleToBinary(bots[i].turnData.robotRightDistanceToWall));
			bots[i].turnData.velocity = splitBinary(doubleToBinary(bots[randomParent].turnData.velocity), doubleToBinary(bots[i].turnData.velocity));*/
		}
		
		for(int i = bots.length - 1; i >= bots.length/elite ; i--){
			bots[i].speedData.bearing = binaryToDouble(mutate(doubleToBinary(bots[i].speedData.bearing)));
			bots[i].speedData.distanceToEnemy = binaryToDouble(mutate(doubleToBinary(bots[i].speedData.distanceToEnemy)));
			bots[i].speedData.headingEnemy = binaryToDouble(mutate(doubleToBinary(bots[i].speedData.headingEnemy)));
			bots[i].speedData.robotBackDistanceToWall = binaryToDouble(mutate(doubleToBinary(bots[i].speedData.robotBackDistanceToWall)));
			bots[i].speedData.robotFrontDistanceToWall = binaryToDouble(mutate(doubleToBinary(bots[i].speedData.robotFrontDistanceToWall)));
			bots[i].speedData.robotLeftDistanceToWall = binaryToDouble(mutate(doubleToBinary(bots[i].speedData.robotLeftDistanceToWall)));
			bots[i].speedData.robotRightDistanceToWall = binaryToDouble(mutate(doubleToBinary(bots[i].speedData.robotRightDistanceToWall)));
			bots[i].speedData.velocity = binaryToDouble(mutate(doubleToBinary(bots[i].speedData.velocity)));
			
			bots[i].turnData.bearing = binaryToDouble(mutate(doubleToBinary(bots[i].turnData.bearing)));
			bots[i].turnData.distanceToEnemy = binaryToDouble(mutate(doubleToBinary(bots[i].turnData.distanceToEnemy)));
			bots[i].turnData.headingEnemy = binaryToDouble(mutate(doubleToBinary(bots[i].turnData.headingEnemy)));
			bots[i].turnData.robotBackDistanceToWall = binaryToDouble(mutate(doubleToBinary(bots[i].turnData.robotBackDistanceToWall)));
			bots[i].turnData.robotFrontDistanceToWall = binaryToDouble(mutate(doubleToBinary(bots[i].turnData.robotFrontDistanceToWall)));
			bots[i].turnData.robotLeftDistanceToWall = binaryToDouble(mutate(doubleToBinary(bots[i].turnData.robotLeftDistanceToWall)));
			bots[i].turnData.robotRightDistanceToWall = binaryToDouble(mutate(doubleToBinary(bots[i].turnData.robotRightDistanceToWall)));
			bots[i].turnData.velocity = binaryToDouble(mutate(doubleToBinary(bots[i].turnData.velocity)));
		}				
		for(int i = 0; i < bots.length; i++)
			System.out.println(bots[i].speedData.bearing);
	}
}